package no.spk.demo.tcalc.amclient;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.jboss.resteasy.client.ClientResponseFailure;
import org.jboss.resteasy.client.ProxyFactory;

public class Am implements AMClient{

    private HttpClient httpClient;
    private AMClient amClient;
    
    private long waitTime = 7000;
    private long maxWaitTime = 30000;
    
    public Am() {
        httpClient = createHttpClient();
        amClient = ProxyFactory.create(AMClient.class, "http://eu.wowarmory.com", httpClient);
    }
    
    private String callRemoteService(File file, Invoker invoker, String[] args){
        String xmlResult = null;
        
        try{
            throttle();              
            xmlResult = invoker.invoke(args);
            waitTime = 7000;
            addToCache(file, xmlResult);
        } catch(ClientResponseFailure crf){
            System.err.println( "Call failed with waitTime: " + waitTime );
            waitTime+=1000;
                        
            if( waitTime > maxWaitTime  )
                throw crf;
            
            xmlResult = callRemoteService( file, invoker, args );
        }
        
        return xmlResult; 
    }
    
    private class GetCharInvoker implements Invoker{
        public String invoke(String... args){
            return amClient.getChar(args[0], args[1] );
        }     
    }
    
    private class GetTalentsInvoker implements Invoker{
        public String invoke(String... args){
            return amClient.getTalents(args[0], args[1], args[2]);
        }     
    }
    
    private class GetItemInvoker implements Invoker{
        public String invoke(String... args){
            return amClient.getItem(args[0]);
        }     
    }
    
    public String getChar(String realm, String charName) {
        File file = new File(realm + "-" + charName);
        String memberXmlResult = null;                
        
        if( isUpdateDaily( file ) ){
            String[] args = {realm, charName};
            memberXmlResult = callRemoteService(file, new GetCharInvoker(), args);                        
        } else {
            memberXmlResult = getFromCache(file);
        }
                
        return memberXmlResult;
    }

    public String getGuild(String realm, String guildName) {
        File file = new File(realm + "-" + guildName);
        String guildXmlResult = null;                
        
        if( isUpdateDaily( file ) ){
            throttle();
            guildXmlResult = amClient.getGuild( realm, guildName );            
            addToCache(file, guildXmlResult);
        } else {
            guildXmlResult = getFromCache(file);
        }
                
        return guildXmlResult;
    }

    public String getTalents(String realm, String charName, String specNumber) {
        File file = new File(realm + "-" + charName + "-" + specNumber);
        String specXmlResult = null;                
        
        if( isUpdateWeekly( file ) ){            
            String[] args = {realm, charName, specNumber};
            specXmlResult = callRemoteService(file, new GetTalentsInvoker(), args);   
        } else {
            specXmlResult = getFromCache(file);
        }
                
        return specXmlResult;
    }
    

    public String getItem(String itemId) {
        File file = new File("item-" + itemId);
        String itemXmlResult = null;                
        
        if( isUpdateNever( file ) ){            
            String[] args = {itemId};
            itemXmlResult = callRemoteService(file, new GetItemInvoker(), args);   
        } else {
            itemXmlResult = getFromCache(file);
        }
                
        return itemXmlResult;
    }
    
    private void addToCache(File file, String guildXmlResult) {
        try {
            FileWriter fWriter = new FileWriter( file );
            fWriter.append( guildXmlResult );
            fWriter.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private String getFromCache(File file) {
        String guildXmlResult = null;
        
        try {
            FileInputStream fInputStream = new FileInputStream (file);

            byte[] b = new byte[fInputStream.available()];
            fInputStream.read(b);
            fInputStream.close ();
            guildXmlResult = new String (b);

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return guildXmlResult;
    }

    private boolean isUpdateDaily(File file) {
        return isUpdate(file, 1000*60*60*24);
    }    

    private boolean isUpdateWeekly(File file) {        
        return isUpdate(file, 1000*60*60*24*7);
    }
    
    private boolean isUpdateNever(File file) {                        
        if( file.exists() )            
            return false;                    
        
        return true;
    }
    
    private boolean isUpdate(File file, long time) {
        boolean update = true;
        
        if( file.exists() ){
            long lastModified = file.lastModified();
            long timeDiff = System.currentTimeMillis() - lastModified;
            
            if( timeDiff < time){ 
                update = false;
            }
        }
        
        return update;
    }

    private HttpClient createHttpClient() {
        HostConfiguration hostConf = new HostConfiguration();
        hostConf.setProxy( "proxy.spk.no", 8080);       
        
        HttpClient httpClient = new HttpClient();
        httpClient.getParams().setParameter("http.useragent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2");
        httpClient.setHostConfiguration(hostConf);
        return httpClient;
    }
    
    private synchronized void throttle(){
        try {
            Thread.sleep(waitTime );
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    

    

}
